package org.zjx.util.clickprecision;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.List;

/**
 * 像素碰撞检测系统 - 在像素坐标系中进行碰撞检测和替代点寻找
 * 使用高效的搜索算法找到最优点击位置
 */
public class PixelCollisionSystem {
    private final int screenWidth;
    private final int screenHeight;

    public PixelCollisionSystem(int screenWidth, int screenHeight) {
        this.screenWidth = screenWidth;
        this.screenHeight = screenHeight;
    }

    /**
     * 检查屏幕位置是否可点击
     */
    public boolean isPositionClickable(Point screenPos, List<Rectangle> blockedAreas) {
        if (!isWithinScreen(screenPos)) return false;

        return blockedAreas.parallelStream()
                .noneMatch(area -> area.contains(screenPos));
    }

    private boolean isWithinScreen(Point screenPos) {
        return screenPos.x >= 0 && screenPos.x < screenWidth &&
                screenPos.y >= 0 && screenPos.y < screenHeight;
    }

    /**
     * 寻找最优点击位置 - 核心算法
     * 1. 先检查原始位置
     * 2. 寻找射线交点
     * 3. 螺旋搜索最近可点击点
     */
    public Point findOptimalClickPosition(Point start, Point target, List<Rectangle> blockedAreas) {
        // 1. 直接检查目标点
        if (isPositionClickable(target, blockedAreas)) {
            return target;
        }

        // 2. 寻找射线交点（保持方向准确性）
        Point intersection = findRayIntersection(start, target, blockedAreas);
        if (intersection != null && isPositionClickable(intersection, blockedAreas)) {
            return intersection;
        }

        // 3. 螺旋搜索（保证找到最近点）
        return spiralSearch(target, blockedAreas, 50);
    }

    /**
     * 计算射线与阻挡区域的交点
     */
    private Point findRayIntersection(Point start, Point end, List<Rectangle> blockedAreas) {
        Point closestIntersection = null;
        double minDistance = Double.MAX_VALUE;

        for (Rectangle area : blockedAreas) {
            Point intersection = calculateLineRectIntersection(start, end, area);
            if (intersection != null && isPointBetween(start, end, intersection)) {
                double distance = start.distance(intersection);
                if (distance < minDistance) {
                    minDistance = distance;
                    closestIntersection = intersection;
                }
            }
        }

        return closestIntersection;
    }

    /**
     * 计算线段与矩形的交点
     */
    private Point calculateLineRectIntersection(Point start, Point end, Rectangle rect) {
        // 检查四条边
        Point[] intersections = {
                intersectWithEdge(start, end, rect.x, rect.y, rect.x + rect.width, rect.y, false), // 上边
                intersectWithEdge(start, end, rect.x, rect.y + rect.height, rect.x + rect.width, rect.y + rect.height, false), // 下边
                intersectWithEdge(start, end, rect.x, rect.y, rect.x, rect.y + rect.height, true), // 左边
                intersectWithEdge(start, end, rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height, true) // 右边
        };

        Point closest = null;
        double minDist = Double.MAX_VALUE;

        for (Point intersection : intersections) {
            if (intersection != null) {
                double dist = start.distance(intersection);
                if (dist < minDist) {
                    minDist = dist;
                    closest = intersection;
                }
            }
        }

        return closest;
    }

    /**
     * 与边界的交点计算
     */
    private Point intersectWithEdge(Point start, Point end, int x1, int y1, int x2, int y2, boolean isVertical) {
        if (isVertical) {
            // 垂直线
            if (start.x == end.x) return null;
            float t = (float) (x1 - start.x) / (end.x - start.x);
            if (t < 0 || t > 1) return null;
            int y = start.y + (int) (t * (end.y - start.y));
            if (y >= y1 && y <= y2) return new Point(x1, y);
        } else {
            // 水平线
            if (start.y == end.y) return null;
            float t = (float) (y1 - start.y) / (end.y - start.y);
            if (t < 0 || t > 1) return null;
            int x = start.x + (int) (t * (end.x - start.x));
            if (x >= x1 && x <= x2) return new Point(x, y1);
        }
        return null;
    }

    /**
     * 检查点是否在线段上
     */
    private boolean isPointBetween(Point start, Point end, Point point) {
        boolean inX = point.x >= Math.min(start.x, end.x) && point.x <= Math.max(start.x, end.x);
        boolean inY = point.y >= Math.min(start.y, end.y) && point.y <= Math.max(start.y, end.y);
        return inX && inY;
    }

    /**
     * 螺旋搜索算法 - 高效寻找最近可点击点
     */
    private Point spiralSearch(Point center, List<Rectangle> blockedAreas, int maxRadius) {
        // 分层搜索，从近到远
        for (int radius = 1; radius <= maxRadius; radius++) {
            Point validPoint = searchAtRadius(center, radius, blockedAreas);
            if (validPoint != null) return validPoint;
        }
        return center; // 保底返回原目标
    }

    /**
     * 在指定半径层搜索
     */
    private Point searchAtRadius(Point center, int radius, List<Rectangle> blockedAreas) {
        // 搜索方形边界，避免内部点
        for (int i = -radius; i <= radius; i++) {
            Point[] candidates = {
                    new Point(center.x + i, center.y - radius), // 上
                    new Point(center.x + i, center.y + radius), // 下
                    new Point(center.x - radius, center.y + i), // 左
                    new Point(center.x + radius, center.y + i)  // 右
            };

            for (Point candidate : candidates) {
                if (isPositionClickable(candidate, blockedAreas)) {
                    return candidate;
                }
            }
        }
        return null;
    }

    /**
     * 批量寻找最优点击位置
     */
    public Point[] findMultipleOptimalPositions(Point start, Point[] targets, List<Rectangle> blockedAreas) {
        Point[] results = new Point[targets.length];
        for (int i = 0; i < targets.length; i++) {
            results[i] = findOptimalClickPosition(start, targets[i], blockedAreas);
        }
        return results;
    }
}